package org.tokaf.bestcolumnfinder;

import java.util.ArrayList;

import org.tokaf.TopKElement;
import org.tokaf.algorithm.Algorithm;
import org.tokaf.datasearcher.DataSearcher;

/**
 * <p>The weight of column is proportional to the number of missing attributes
 * in top-k set. Search for missing attributes starts from k-th element and goes
 * to (k-depth)-th element. </p> <p>Copyright (c) 2006</p>
 * @author Alan Eckhardt
 * @version 1.0
 */
public class MissingValuesFinder implements BestColumnFinder {

	int count[];

	int countNull[];

	int depth = 10;

	protected BestColumnFinder derivation;

	protected void setDerivation(DataSearcher data[], Algorithm alg) {
		derivation = new DerivationInPointFinder(data, alg.getRater());
	}

	protected boolean checkFinish(DataSearcher[] data) {
		for (int i = 0; i < data.length; i++)
			if (data[i].hasNext())
				return false;

		return true;
	}

	/**
	 * Computes number of missing atributes for each column in top-k set.
	 * @param al The set to be searched.
	 * @param K The position, from which the search is started.
	 */
	public void getNulls(ArrayList al, int K) {
		if (al.size() <= K)
			return;

		for (int i = 0; i < countNull.length; i++)
			countNull[i] = 0;

		for (int j = 0; j < countNull.length; j++)
			for (int i = Math.max(K - depth, 0); i < K; i++) {
				if (((TopKElement) al.get(i)).isNull(j)) {
					countNull[j] = 1 + i;
					break;
				}
			}
		return;
	}

	/**
	 * findColumn
	 * @param alg Algorithm
	 * @return int
	 */
	public int findColumn(Algorithm alg) {
		DataSearcher[] data = alg.getDataSearchers();
		if (derivation == null)
			setDerivation(data, alg);
		if (checkFinish(data))
			return -1;

		if (count == null)
			count = new int[data.length];
		if (countNull == null)
			countNull = new int[data.length];

		int index = 0;

		for (int i = 0; i < data.length; i++)
			if (!data[i].hasNext())
				count[i] = 0;

		ArrayList al = alg.getTopK();
		// Computes the number of m.a., which is stored in countNull.
		getNulls(al, alg.getK());
		boolean nonZero = false;

		for (int i = 0; i < count.length; i++) {
			// We accumulates the number of missing attributes, so the column
			// with few m.a. will be chosen some time
			count[i] += (double) countNull[i];
			if (count[index] < count[i] && data[i].hasNext())
				index = i;
			if (countNull[i] != 0)
				nonZero = true;
		}

		// There are no missing values, or the choosen list is at the end
		if (nonZero == false || !data[index].hasNext()) {
			return derivation.findColumn(alg);
		} else
			count[index] = 0;

		return index;
	}

	public int getDepth() {
		return depth;
	}

	public void setDepth(int depth) {
		this.depth = depth;
	}
}
